﻿
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace library
{
    static class LocalIndex
    {
        static List<IndexItem> index = new List<IndexItem>();

        static IndexItem[] last_item = new IndexItem[Parameters.semanticSearchReferences];

        static byte[] last_address = new byte[0];

        static byte last_item_offset;

        internal static void AddReference(string term, string reference, byte initial_hits = 1)
        {
            lock (index)
            {
                IndexItem item = index.FirstOrDefault(x => Addresses.Equals(x.Term, term));

                if (item == null)
                {
                    item = new IndexItem(term, null);

                    index.Add(item);
                }

                IndexItem target = index.FirstOrDefault(x => Addresses.Equals(x.Term, term));

                if (target == null)
                {
                    target = new IndexItem(reference, null);

                    index.Add(target);
                }

                item.AddReference(target);
            }
        }

        internal static void AddAddress(string term, byte[] address)
        {
            lock (index)
            {
                IndexItem item = index.FirstOrDefault(x => Addresses.Equals(x.Term, term));

                if (item == null)
                {
                    item = new IndexItem(term, address);

                    index.Add(item);
                }
                else
                {
                    item.AddAddress(address);
                }

                if (last_item[last_item_offset] == null ||
                    (Addresses.Compare(last_address, address) > 0))
                {
                    last_item[last_item_offset] = null;

                    last_item_offset++;

                    if (last_item_offset == Parameters.semanticSearchReferences)
                        last_item_offset = 0;

                    last_item[last_item_offset] = item;

                    last_address = address;

                    return;
                }

                last_address = address;

                int i = -1;

                while (i != last_item_offset)
                {
                    if (i == -1)
                        i = last_item_offset;

                    if (last_item[i] == null)
                        break;

                    last_item[i].AddReference(item);

                    i--;

                    if (i == -1)
                        i = Parameters.semanticSearchReferences - 1;
                }

                last_item_offset++;

                if (last_item_offset == Parameters.semanticSearchReferences)
                    last_item_offset = 0;

                last_item[last_item_offset] = item;
            }
        }

        internal static IndexItem Get(string term)
        {
            lock(index)
                return index.FirstOrDefault(x => x.Term.IndexOf(term) > -1);
        }

        internal static ValueHits<p2pPost> SearchByTargetAddress(byte[] address)
        {
            lock (index)
                index.ForEach(x => x.References.ForEach(y => y.Hits--));

            var result = new ValueHits<p2pPost>();

            lock (index)
                index.ForEach(x =>
                {
                    List<byte[]> xAddress;

                    lock (x.Addresses)
                        xAddress = x.Addresses.ToList();

                    xAddress.ForEach(y =>
                    {
                        if (Addresses.Equals(y, address))
                        {
                            result.Add(LocalPosts.Get(y));

                            //x.GetReferences(result);
                        }
                    });
                });

            return result;
        }

        internal static ValueHits<p2pPost> SearchPostsAddressesByTerm(string term)
        {
            lock (index)
                index.ForEach(x => x.References.ForEach(y => y.Hits--));

            var result = new ValueHits<p2pPost>();


            List<IndexItem> indexes;
            
            lock(index)
                indexes = index.Where(x =>
                    x.Term.IndexOf(term) > -1).ToList();

            foreach (IndexItem item in indexes)
            {
                List<byte[]> xAddress;

                lock (item.Addresses)
                    xAddress = item.Addresses.ToList();

                    xAddress.ForEach(x => result.Add(LocalPosts.Get(x)));

                //var references = new ValueHits<IndexItem>();
                
                //item.GetReferences(references);
                
                //foreach (var i in references)
                //{
                //    index.ForEach(x =>
                //        x.References.ForEach(y => {
                //            lock(y.Addresses)
                //            {
                //                y.Addresses.ForEach(w =>
                //                {
                //                    if (Addresses.Equals(y.t, i.Value))
                //                        result.Add(LocalPosts.Get(w));
                //                });
                //            }
                //        }));
                //}
            }


            return result.Tops();
        }

        internal static void ParseContent(byte[] address, string content)
        {
            string[] ss = content.Split(' ');

            foreach (string s in ss)
            {
                AddAddress(s, address);
            }
        }

        //internal static void Save()
        //{
        //    foreach (IndexItem item in index)
        //    {
        //        item.Save();
        //    }
        //}
    }


}
